package com.columboid.web.helper;

import java.io.StringReader;
import java.security.NoSuchAlgorithmException;

import javax.xml.bind.JAXBException;

import org.xml.sax.SAXException;

import com.columboid.protocol.syncml.ClientCredential;
import com.columboid.protocol.syncml.CredentialType;
import com.columboid.protocol.syncml.ServerAuthentication;
import com.columboid.protocol.syncml.helper.EncryptionHelper;
import com.columboid.protocol.syncml.helper.JaxbHelper;
import com.columboid.protocol.syncml.metainfo.MetInf;
import com.columboid.protocol.syncml.metainfo.NextNonce;
import com.columboid.protocol.syncml.metainfo.ObjectFactory;
import com.columboid.protocol.syncml.representation.Key;
import com.columboid.protocol.syncml.representation.SyncML;
import com.columboid.web.resource.Response;

public class RequestHelper {

	public static String getStringFromSyncMLObject(SyncML requestSml)
			throws Exception {

		String requestUser = requestSml.getSyncHdr().getSource().getLocName();

		String requestToken = "";
		int statusCode = Response.OK;
		String requestedUserpassword = "";
		if (requestSml.getSyncHdr().getCred() != null) {
			requestToken = requestSml.getSyncHdr().getCred().getData();
			ServerAuthentication authentication = new ServerAuthentication();
			ClientCredential credential = new ClientCredential();
			requestedUserpassword = DataStorage.getPassword(requestUser);
			credential.setHashPassword(requestedUserpassword);
			credential.setNonceToken(DataStorage.getToken(requestUser));
			credential.setUserName(requestUser);
			Boolean result;
			String publicKey = "";
			java.util.List<Object> list = requestSml.getSyncBody()
					.getKeyOrRoutingOrAlert();
			for (int i = 0; i < list.size(); i++) {
				Object obj = list.get(i);
				if (obj instanceof Key) {
					publicKey = ((Key) obj).getData();
				}
			}
			result = authentication.checkCredential(credential, requestToken);

			if (result) {
				if (publicKey.length() > 0) {
					if (!DataStorage.saveClientPublicKey(requestUser, publicKey)) {
						throw new Exception(
								"Failed to save the client public key");
					}
					statusCode = Response.OK;
				} else if (DataStorage.checkClientPublicKey(requestUser)) {
					statusCode = Response.OK;
				} else {
					statusCode = Response.RequireKey;
				}
			} else {
				statusCode = Response.Unauthorized;
			}
		} else {
			statusCode = Response.CredentialMissing;
		}
		String serverChallenge = "";
		if(statusCode!=Response.CredentialMissing)
		{
			String requestMeta = requestSml.getSyncHdr().getCred().getMeta();
			
			if (requestMeta != null) {
				// If the credential meta value is not empty, the the server should
				// check whether the client requires the token verification or not
				String xml = requestMeta;
				String xsd = JaxbHelper.getMetaSchema();

				StringReader xmlReader = new StringReader(xml);
				StringReader xsdReader = new StringReader(xsd);
				try {
					MetInf metaSml = JaxbHelper.CreateSyncMLObject(xmlReader,
							xsdReader, MetInf.class, ObjectFactory.class);
					NextNonce requestNonce = metaSml.getNextNonce();
					if (requestNonce != null) {
						// If the client required the token, then the server should
						// respond with the proper challenge

						serverChallenge = EncryptionHelper.GetHashString(
								requestUser, requestedUserpassword, requestNonce
										.getContent(), CredentialType.MD5);

					}
				} catch (JAXBException e) {
					throw new JAXBException(e);
				} catch (SAXException e) {
					throw new SAXException(e);
				} catch (NoSuchAlgorithmException e) {
					throw new NoSuchAlgorithmException(e);
				} catch (Exception e) {
					throw new Exception(e);
				} finally {
					xmlReader.close();
					xsdReader.close();
				}
			}
	
		}
				int sessionId = Integer
				.parseInt(requestSml.getSyncHdr().getSessionID());
		int msgId = Integer.parseInt(requestSml.getSyncHdr().getMsgID());
		String nonce = DataStorage.setToken(requestUser);
		String clientUri = requestSml.getSyncHdr().getSource().getLocURI();
		String serverUri = DataStorage.getServiceAddr(requestUser);

		SyncML responseSml = JaxbHelper.getServerResponse(sessionId, msgId,
				serverChallenge, nonce, clientUri, serverUri, String
						.valueOf(statusCode));
		Boolean isFinal = false;
		if (statusCode == Response.OK) {
			isFinal = true;
		}
		String serverResponse = JaxbHelper.getJaxbObjectString(responseSml,
				isFinal);
		return serverResponse;
	}
}
